﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data.SqlClient;
using System.Linq;
using NOSDC.Entities;
using NOSDC.Pocos;
using System.Data.Objects;
using System.Data;

namespace NOSDC.Repositories
{
    public sealed class EventsRepository : IEventsRepository
    {
        private readonly NOSDCContext _context;

        //TODO: Refactor for testing. Implement Interfaces
        public EventsRepository()
        {
            _context = new NOSDCContext();
        }

        public IEnumerable<Events> GetAllEvents()
        {
            return _context.Events.OrderByDescending(e => e.StartDate).ToList();
        }

        public Events GetUpcomingEvent()
        {
            var ev = _context.Events.Where(e => e.StatusID == 1)
                                    .Where(e => e.StartDate > DateTime.Now)
                                    .OrderBy(e => e.StartDate)
                                    .Take(1).FirstOrDefault();
            return ev;
        }

        public IEnumerable<Events> GetAllUpcomingEvents()
        {
            var ev = _context.Events.Where(e => e.StatusID == 1)
                                    .Where(e => e.StartDate > DateTime.Now)
                                    .OrderBy(e => e.StartDate);
            return ev;
        }

        public int CreateEvent(Events e)
        {
            using (var context = new NOSDCContext())
            {
                context.Events.AddObject(e);
                return context.SaveChanges();
            }
        }

        public int CreateEvent(Events e, List<int> sponsorids, List<int> speakerids)
        {
            using (var context = new NOSDCContext())
            {
                if (sponsorids != null)
                {
                    foreach (int s in sponsorids)
                    {
                        e.Sponsors.Add(context.Sponsor.FirstOrDefault(sp => sp.SponsorId == s));
                    }
                }

                if (speakerids != null)
                {
                    foreach (var i in speakerids)
                        e.Speakers.Add(context.Speaker.FirstOrDefault(s => s.SpeakerId == i));
                }

                context.Events.AddObject(e);
                return context.SaveChanges();
            }
        }

        public int UpdateEvent(Events e)
        {
            _context.Events.Attach(e);
            var eventsEntry = _context.ObjectStateManager.GetObjectStateEntry(e);
            eventsEntry.SetModified();
            _context.ObjectStateManager.ChangeObjectState(e, EntityState.Modified);
            return _context.SaveChanges(SaveOptions.DetectChangesBeforeSave);
        }

        public int UpdateEvent(Events e, List<int> sponsorids, List<int> speakerids)
        {
            using(var context = new NOSDCContext())
            {
                UpdateSponsorIds(e.EventID, sponsorids);
                UpdateSpeakerIds(e.EventID, speakerids);

                e.Speakers = new List<Speaker>();
                foreach (var i in speakerids)
                {
                    e.Speakers.Add(context.Speaker.Single(id => id.SpeakerId == i));
                }

                context.Events.Attach(e);
                var eventsEntry = context.ObjectStateManager.GetObjectStateEntry(e);

                context.ObjectStateManager.ChangeObjectState(e, EntityState.Modified);
                eventsEntry.SetModified();

                return context.SaveChanges(SaveOptions.DetectChangesBeforeSave);
            }
        }

        private void UpdateSpeakerIds(int eventId, IEnumerable<int> speakerids)
        {
            var connectionString = ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString;
            using (var conn = new SqlConnection(connectionString))
            {
                using (var cmd = new SqlCommand("", conn))
                {
                    cmd.CommandText = "DELETE FROM EventSpeakers WHERE EventId = @EventId";
                    cmd.Parameters.AddWithValue("@EventId", eventId);

                    conn.Open();
                    cmd.ExecuteNonQuery();
                }

                foreach (var i in speakerids)
                {
                    using (var cmd = new SqlCommand("", conn))
                    {
                        cmd.CommandText = "INSERT INTO EventSpeakers VALUES(@EventId, @SpeakerId)";
                        cmd.Parameters.AddWithValue("@EventId", eventId);
                        cmd.Parameters.AddWithValue("@SpeakerId", i);

                        cmd.ExecuteNonQuery();
                    }
                }
            }
        }

        private void UpdateSponsorIds(int eventId, IEnumerable<int> sponsorids)
        {
            var connectionString = ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString;
            using (var conn = new SqlConnection(connectionString))
            {
                using(var cmd = new SqlCommand("", conn))
                {
                    cmd.CommandText = "DELETE FROM EventSponsors WHERE EventId = @EventId";
                    cmd.Parameters.AddWithValue("@EventId", eventId);

                    conn.Open();
                    cmd.ExecuteNonQuery();
                }

                foreach(var i in sponsorids)
                {
                    using (var cmd = new SqlCommand("", conn))
                    {
                        cmd.CommandText = "INSERT INTO EventSponsors VALUES(@EventId, @SponsorId)";
                        cmd.Parameters.AddWithValue("@EventId", eventId);
                        cmd.Parameters.AddWithValue("@SponsorId", i);

                        cmd.ExecuteNonQuery();
                    }
                }
            }
        }

        private void UpdateSpeakerIds()
        {
            
        }

        public Events GetEventByID(int id)
        {
            return _context.Events.FirstOrDefault(e => e.EventID.Equals(id));
        }

        public bool AttendEvent(Guid userid, int eventId)
        {
            _context.EventAttendees.AddObject(new EventAttendee { EventID = eventId, UserID = userid });
            return _context.SaveChanges() > 0;
        }

        public void FinalizeEvent(IList<FinalEventAttendee> attendees, int eventId)
        {
            var allExistingAttendees = _context.FinalEventAttendees.Where(e => e.EventId.Equals(eventId));

            foreach(var i in allExistingAttendees)
                _context.FinalEventAttendees.DeleteObject(i);

            using (var context = new NOSDCContext())
            {
                foreach(var i in attendees)
                    context.FinalEventAttendees.AddObject(i);
                
                context.SaveChanges();
            }

            var ev = GetEventByID(eventId);
            ev.Finalized = true;
            UpdateEvent(ev);
        }

        public bool IsAttendingEvent(int eventID, Guid userID)
        {
            return _context.EventAttendees.Count(e => e.EventID.Equals(eventID) && e.UserID.Equals(userID)) == 1;
        }

        public IList<EventAttendee> GetAttendees(int eventId)
        {
            return _context.EventAttendees.Where(e => e.EventID.Equals(eventId)).ToList();
        }

        public IList<FinalEventAttendee> GetFinalAttendees(int eventId)
        {
            return _context.FinalEventAttendees.Where(e => e.EventId.Equals(eventId)).ToList();
        }

        public IEnumerable<Events> GetPreviousEvents(int numberOfEvents)
        {
            return _context.Events.Where(e => e.StatusID == 1)
                                    .Where(e => e.StartDate < DateTime.Now)
                                    .OrderByDescending(e => e.StartDate)
                                    .Take(numberOfEvents);
        }

        public IList<Events> GetEventsByPage(int page, int pageSize)
        {
            var events = _context.Events.Where(c => c.StatusID.Equals(1))
                                        .OrderByDescending(c => c.StartDate)
                                        .Skip((page - 1) * pageSize).Take(pageSize).ToList();
            return events;
        }


        public int GeTotalEvents()
        {
            return _context.Events.Count();
        }
    }
}
